home *** CD-ROM | disk | FTP | other *** search
/ Amiga Format CD 7 / Amiga Format AFCD07 (Dec 1996, Issue 91).iso / serious / shareware / programming / emacs-complete / fsf / emacs / oldxmenu / internal.c < prev    next >
C/C++ Source or Header  |  1993-07-30  |  27KB  |  997 lines

  1. #include "copyright.h"
  2.  
  3. /* $Header: /u/src/emacs/19.0/oldXMenu/RCS/Internal.c,v 1.1 1992/04/11 22:10:20 jimb Exp $ */
  4. /* Copyright    Massachusetts Institute of Technology    1985    */
  5.  
  6. /*
  7.  * XMenu:    MIT Project Athena, X Window system menu package
  8.  *
  9.  *     XMenuInternal.c - XMenu internal (not user visable) routines.
  10.  *
  11.  *    Author:        Tony Della Fera, DEC
  12.  *            November, 1985
  13.  *
  14.  */
  15.  
  16. #include "XMenuInt.h"
  17.  
  18. /*
  19.  * Toggle color macro.
  20.  */
  21. #define toggle_color(x) \
  22.     ((x) == menu->bkgnd_color ? menu->s_frg_color : menu->bkgnd_color)
  23.  
  24. /*
  25.  * Internal Window creation queue sizes.
  26.  */
  27. #define S_QUE_SIZE    300
  28. #define P_QUE_SIZE    20
  29. #define BUFFER_SIZE    (S_QUE_SIZE >= P_QUE_SIZE ? S_QUE_SIZE : P_QUE_SIZE)
  30.  
  31.  
  32. /*
  33.  * XMWinQue - Internal window creation queue datatype.
  34.  */
  35. typedef struct _xmwinquedef {
  36.     int sq_size;
  37.     XMSelect *sq[S_QUE_SIZE];
  38.     XMSelect **sq_ptr;
  39.     int pq_size;
  40.     XMPane *pq[P_QUE_SIZE];
  41.     XMPane **pq_ptr;
  42. } XMWinQue;
  43.  
  44. /*
  45.  * _XMWinQue - Internal static window creation queue.
  46.  */
  47. static Bool _XMWinQueIsInit = False;
  48. static XMWinQue _XMWinQue;
  49.  
  50. /*
  51.  * _XMErrorCode - Global XMenu error code.
  52.  */
  53. int _XMErrorCode = XME_NO_ERROR; 
  54. /*
  55.  * _XMErrorList - Global XMenu error code description strings.
  56.  */
  57. char *
  58. _XMErrorList[XME_CODE_COUNT] = {
  59.     "No error",                /* XME_NO_ERROR */
  60.     "Menu not initialized",        /* XME_NOT_INIT */
  61.     "Argument out of bounds",        /* XME_ARG_BOUNDS */
  62.     "Pane not found",            /* XME_P_NOT_FOUND */
  63.     "Selection not found",        /* XME_S_NOT_FOUND */
  64.     "Invalid menu style parameter",    /* XME_STYLE_PARAM */
  65.     "Unable to grab mouse",        /* XME_GRAB_MOUSE */
  66.     "Unable to interpret locator",    /* XME_INTERP_LOC */
  67.     "Unable to calloc memory",        /* XME_CALLOC */
  68.     "Unable to create XAssocTable",    /* XME_CREATE_ASSOC */
  69.     "Unable to store bitmap",        /* XME_STORE_BITMAP */
  70.     "Unable to make tile pixmaps",    /* XME_MAKE_TILES */
  71.     "Unable to make pixmap",        /* XME_MAKE_PIXMAP */
  72.     "Unable to create cursor",        /* XME_CREATE_CURSOR */
  73.     "Unable to open font",        /* XME_OPEN_FONT */
  74.     "Unable to create windows",        /* XME_CREATE_WINDOW */
  75.     "Unable to create transparencies",    /* XME_CREATE_TRANSP */
  76. };
  77.  
  78. /*
  79.  * _XMEventHandler - Internal event handler variable.
  80.  */
  81. int (*_XMEventHandler)() = NULL;
  82.  
  83.  
  84.  
  85. /*
  86.  * _XMWinQueInit - Internal routine to initialize the window
  87.  *           queue.
  88.  */
  89. _XMWinQueInit()
  90. {
  91.     /*
  92.      * If the queue is not initialized initialize it.
  93.      */
  94.     if (!_XMWinQueIsInit) {
  95.     /*
  96.      * Blank the queue structure.
  97.      */
  98.     register int i;
  99.  
  100.     for (i = 0; i < S_QUE_SIZE; i++)
  101.       _XMWinQue.sq[i] = 0;
  102.  
  103.     for (i = 0; i < P_QUE_SIZE; i++)
  104.       _XMWinQue.pq[i] = 0;
  105.  
  106.     _XMWinQue.sq_size = _XMWinQue.pq_size = 0;
  107.  
  108.     /*
  109.      * Initialize the next free location pointers.
  110.      */
  111.     _XMWinQue.sq_ptr = _XMWinQue.sq;
  112.     _XMWinQue.pq_ptr = _XMWinQue.pq;
  113.     }
  114. }
  115.  
  116.  
  117.  
  118. /*
  119.  * _XMWinQueAddPane - Internal routine to add a pane to the pane
  120.  *              window queue.
  121.  */
  122. int
  123. _XMWinQueAddPane(display, menu, p_ptr)
  124.     register Display *display;
  125.     register XMenu *menu;    /* Menu being manipulated. */
  126.     register XMPane *p_ptr;    /* XMPane being queued. */
  127. {
  128.     /*
  129.      * If the queue is currently full then flush it.
  130.      */
  131.     if (_XMWinQue.pq_size == P_QUE_SIZE) {
  132.     if (_XMWinQueFlush(display, menu, 0, 0) == _FAILURE) return(_FAILURE);
  133.     }
  134.  
  135.     /*
  136.      * Insert the new XMPane pointer and increment the queue pointer
  137.      * and the queue size.
  138.      */
  139.     *_XMWinQue.pq_ptr = p_ptr;
  140.     _XMWinQue.pq_ptr++;
  141.     _XMWinQue.pq_size++;
  142.  
  143.     /*
  144.      * All went well, return successfully.
  145.      */
  146.     _XMErrorCode = XME_NO_ERROR;
  147.     return(_SUCCESS);
  148. }
  149.  
  150.  
  151.  
  152. /*
  153.  * _XMWinQueAddSelection - Internal routine to add a selection to
  154.  *               the selection window queue.
  155.  */
  156. int
  157. _XMWinQueAddSelection(display, menu, s_ptr)
  158.     register Display *display;
  159.     register XMenu *menu;    /* Menu being manipulated. */
  160.     register XMSelect *s_ptr;    /* XMSelection being queued. */
  161. {
  162.     /*
  163.      * If this entry will overflow the queue then flush it.
  164.      */
  165.     if (_XMWinQue.sq_size == S_QUE_SIZE) {
  166.     if (_XMWinQueFlush(display, menu, 0, 0) == _FAILURE) return(_FAILURE);
  167.     }
  168.  
  169.     /*
  170.      * Insert the new XMSelect pointer and increment the queue pointer
  171.      * and the queue size.
  172.      */
  173.     *_XMWinQue.sq_ptr = s_ptr;
  174.     _XMWinQue.sq_ptr++;
  175.     _XMWinQue.sq_size++;
  176.  
  177.     /*
  178.      * All went well, return successfully.
  179.      */
  180.     _XMErrorCode = XME_NO_ERROR;
  181.     return(_SUCCESS);
  182. }
  183.  
  184.  
  185.  
  186. /*
  187.  * _XMWinQueFlush - Internal routine to flush the pane and
  188.  *            selection window queues.
  189.  */
  190. int
  191. _XMWinQueFlush(display, menu, pane, select)
  192.     register Display *display;
  193.     register XMenu *menu;        /* Menu being manipulated. */
  194.     register XMPane *pane;        /* Current pane. */
  195. {
  196.     register int pq_index;        /* Pane queue index. */
  197.     register int sq_index;        /* Selection queue index. */
  198.     register XMPane *p_ptr;        /* XMPane pointer. */
  199.     register XMSelect *s_ptr;       /* XMSelect pointer. */
  200.     unsigned long valuemask;        /* Which attributes to set. */
  201.     XSetWindowAttributes *attributes;     /* Attributes to be set. */
  202.  
  203.     /*
  204.      * If the pane window queue is not empty...
  205.      */
  206.     
  207.     if (_XMWinQue.pq_size > 0) {
  208.     /*
  209.      * set up attributes for pane window to be created.
  210.      */
  211.     valuemask = (CWBackPixmap | CWBorderPixel | CWOverrideRedirect);
  212.     attributes = (XSetWindowAttributes *)malloc(sizeof(XSetWindowAttributes));
  213.     attributes->border_pixel = menu->p_bdr_color;
  214.     attributes->background_pixmap = menu->inact_pixmap;
  215.     attributes->override_redirect = True;
  216.     
  217.     /*
  218.      * Create all the pending panes in order, so that the
  219.      * current pane will be on top, with the others
  220.      * stacked appropriately under it.
  221.      */
  222.     for (pq_index = _XMWinQue.pq_size - 1;
  223.          pq_index >= 0;
  224.          pq_index--) 
  225.       {
  226.           p_ptr = _XMWinQue.pq[pq_index];  /* Retrieve next pane. */
  227.           if (p_ptr == pane) break;
  228.           p_ptr->window = XCreateWindow(display,
  229.                         menu->parent,
  230.                         p_ptr->window_x,
  231.                         p_ptr->window_y,
  232.                         p_ptr->window_w,
  233.                         p_ptr->window_h,
  234.                         menu->p_bdr_width,
  235.                         CopyFromParent,
  236.                         InputOutput,
  237.                         CopyFromParent,
  238.                         valuemask,
  239.                         attributes);
  240.           XMakeAssoc(display, menu->assoc_tab, p_ptr->window, p_ptr);
  241.           XSelectInput(display, p_ptr->window, menu->p_events);
  242.       }
  243.     for (pq_index = 0;
  244.          pq_index < _XMWinQue.pq_size;
  245.          pq_index++) 
  246.       {
  247.           p_ptr = _XMWinQue.pq[pq_index];    /* Retrieve next pane. */
  248.           p_ptr->window = XCreateWindow(display,
  249.                         menu->parent,
  250.                         p_ptr->window_x,
  251.                         p_ptr->window_y,
  252.                         p_ptr->window_w,
  253.                         p_ptr->window_h,
  254.                         menu->p_bdr_width,
  255.                         CopyFromParent,
  256.                         InputOutput,
  257.                         CopyFromParent,
  258.                         valuemask,
  259.                         attributes);
  260.           XMakeAssoc(display, menu->assoc_tab, p_ptr->window, p_ptr);
  261.           XSelectInput(display, p_ptr->window, menu->p_events);
  262.           if (p_ptr == pane) break;
  263.     }
  264.  
  265.     /*
  266.      * Reset the pane queue pointer and size.
  267.      */
  268.     _XMWinQue.pq_size = 0;
  269.     _XMWinQue.pq_ptr = _XMWinQue.pq;
  270.     }
  271.  
  272.     /*
  273.      * If the selection window queue is not empty...
  274.      */
  275.     
  276.     if (_XMWinQue.sq_size > 0) {
  277.  
  278.     for (sq_index = 0; sq_index < _XMWinQue.sq_size; sq_index++) {
  279.         /*
  280.          * Retrieve the XMSelect pointer.
  281.          */
  282.         s_ptr = _XMWinQue.sq[sq_index];
  283.         s_ptr->window = XCreateWindow(display,
  284.                    s_ptr->parent_p->window,
  285.                    s_ptr->window_x,
  286.                    s_ptr->window_y,
  287.                    s_ptr->window_w,
  288.                    s_ptr->window_h,
  289.                    0,                /* border width*/
  290.                    CopyFromParent,
  291.                    InputOnly,
  292.                    CopyFromParent,
  293.                    0,
  294.                    attributes);
  295.         
  296.         /*
  297.          * Insert the new window id and its
  298.          * associated XMSelect structure into the 
  299.          * association table.
  300.          */
  301.         XMakeAssoc(display, menu->assoc_tab, s_ptr->window, s_ptr);
  302.         XSelectInput(display, s_ptr->window, menu->s_events);
  303.     }
  304.  
  305.     /*
  306.      * Reset the selection queue pointer and size.
  307.      */
  308.     _XMWinQue.sq_size = 0;
  309.     _XMWinQue.sq_ptr = _XMWinQue.sq;
  310.     }
  311.  
  312.     /*
  313.      * Flush X's internal queues.
  314.      */
  315.     XFlush(display);
  316.  
  317.     /*
  318.      * All went well, return successfully.
  319.      */
  320.     _XMErrorCode = XME_NO_ERROR;
  321.     return(_SUCCESS);
  322. }
  323.  
  324.  
  325.  
  326. /*
  327.  * _XMGetPanePtr -     Given a menu pointer and a pane index number, return
  328.  *            a pane pointer that points to the indexed pane.
  329.  */
  330. XMPane *
  331. _XMGetPanePtr(menu, p_num)
  332.     register XMenu *menu;    /* Menu to find the pane in. */
  333.     register int p_num;        /* Index number of pane to find. */
  334. {
  335.     register XMPane *p_ptr;    /* Pane pointer to be returned. */
  336.     register int i;        /* Loop counter. */
  337.  
  338.     /*
  339.      * Is the pane number out of range?
  340.      */
  341.     if ((p_num < 0) || (p_num > (menu->p_count - 1))) {
  342.     _XMErrorCode = XME_P_NOT_FOUND;
  343.     return(NULL);
  344.     }
  345.  
  346.     /*
  347.      * Find the right pane.
  348.      */
  349.     p_ptr = menu->p_list->next;
  350.     for (i = 0; i < p_num; i++) p_ptr = p_ptr->next;
  351.  
  352.     /*
  353.      * Return successfully.
  354.      */
  355.     _XMErrorCode = XME_NO_ERROR;
  356.     return(p_ptr);
  357. }
  358.  
  359.  
  360.  
  361. /*
  362.  * _XMGetSelectionPtr -    Given pane pointer and a selection index number,
  363.  *            return a selection pointer that points to the
  364.  *            indexed selection.
  365.  */
  366. XMSelect *
  367. _XMGetSelectionPtr(p_ptr, s_num)
  368.     register XMPane *p_ptr;    /* Pane to find the selection in. */
  369.     register int s_num;        /* Index number of the selection to find. */
  370. {
  371.     register XMSelect *s_ptr;    /* Selection pointer to be returned. */
  372.     register int i;        /* Loop counter. *./
  373.     
  374.     /*
  375.      * Is the selection number out of range?
  376.      */
  377.     if ((s_num < 0) || (s_num > (p_ptr->s_count - 1))) {
  378.     _XMErrorCode = XME_S_NOT_FOUND;
  379.     return(NULL);
  380.     }
  381.  
  382.     /*
  383.      * Find the right selection.
  384.      */
  385.     s_ptr = p_ptr->s_list->next;
  386.     for (i = 0; i < s_num; i++) s_ptr = s_ptr->next;
  387.  
  388.     /*
  389.      * Return successfully.
  390.      */
  391.     _XMErrorCode = XME_NO_ERROR;
  392.     return(s_ptr);
  393. }
  394.  
  395.  
  396.  
  397. /*
  398.  * _XMRecomputeGlobals - Internal subroutine to recompute menu wide
  399.  *             global values.
  400.  */
  401. _XMRecomputeGlobals(display, menu)
  402.     register Display *display; /*X11 display variable. */    
  403.     register XMenu *menu;    /* Menu object to compute from. */
  404. {
  405.     register XMPane *p_ptr;    /* Pane pointer. */
  406.     register XMSelect *s_ptr;    /* Selection pointer. */
  407.  
  408.     register int max_p_label = 0;    /* Maximum pane label width. */
  409.     register int max_s_label = 0;    /* Maximum selection label width. */
  410.     register int s_count = 0;        /* Maximum selection count. */
  411.  
  412.     int p_s_pad;        /* Pane <-> selection padding. */
  413.     int p_s_diff;        /* Pane <-> selection separation. */
  414.  
  415.     int p_height;        /* Pane window height. */
  416.     int p_width;        /* Pane window width. */
  417.     int s_width;        /* Selection window width. */
  418.  
  419.     int screen;            /* DefaultScreen holder. */
  420.     
  421.     /*
  422.      * For each pane...
  423.      */
  424.     for (
  425.     p_ptr = menu->p_list->next;
  426.     p_ptr != menu->p_list;
  427.     p_ptr = p_ptr->next
  428.     ){
  429.     
  430.     /*
  431.      * Recompute maximum pane label width.
  432.      */
  433.     max_p_label = max(max_p_label, p_ptr->label_width);
  434.  
  435.     /*
  436.      * Recompute maximum selection count. 
  437.      */
  438.     s_count = max(s_count, p_ptr->s_count);
  439.  
  440.     /*
  441.      * For each selection in the current pane...
  442.      */
  443.     for (
  444.         s_ptr = p_ptr->s_list->next;
  445.         s_ptr != p_ptr->s_list;
  446.         s_ptr = s_ptr->next
  447.     ){
  448.  
  449.         /*
  450.          * Recompute maximum selection label width.
  451.          */
  452.         max_s_label = max(max_s_label, s_ptr->label_width);
  453.     }
  454.     }
  455.  
  456.     /*
  457.      * Recompute pane height.
  458.      */
  459.     p_height = (menu->flag_height << 1) + (menu->s_y_off * s_count);
  460.  
  461.     /*
  462.      * Recompute horizontal padding between the pane window and the
  463.      * selection windows.
  464.      */
  465.     p_s_pad = menu->p_x_off << 1;
  466.  
  467.     /*
  468.      * Recompute pane and selection window widths.
  469.      * This is done by first computing the window sizes from the maximum
  470.      * label widths.  If the spacing between the selection window and the
  471.      * containing pane window is less than the pane selection padding value
  472.      * (twice the pane X offset) then change the size of the pane to be
  473.      * the size of the selection window plus the padding.  If, however the
  474.      * spacing between the selection window and the containing pane window
  475.      * is more than the pane selection padding value increase the size of
  476.      * the selection to its maximum possible value (the pane width minus
  477.      * the pane selection padding value).
  478.      */
  479.     p_width = max_p_label + p_s_pad;
  480.     s_width = max_s_label + (menu->s_fnt_pad << 1) + (menu->s_bdr_width << 1);
  481.     p_s_diff = p_width - s_width;
  482.     if (p_s_diff < p_s_pad) {
  483.     p_width = s_width + p_s_pad;
  484.     }
  485.     else if (p_s_diff > p_s_pad) {
  486.     s_width = p_width - p_s_pad;
  487.     }
  488.  
  489.     /*
  490.      * Reset menu wide global values.
  491.      */
  492.     menu->s_count = s_count;
  493.     menu->p_height = p_height;
  494.     menu->p_width = p_width;
  495.     menu->s_width = s_width;
  496.  
  497.     /* 
  498.      * Ensure that the origin of the menu is placed so that
  499.      * None of the panes ore selections are off the screen.
  500.      */
  501.     screen = DefaultScreen(display);
  502.     if (menu->x_pos + menu->width > DisplayWidth(display, screen))
  503.         menu->x_pos = DisplayWidth(display, screen) - menu->width;
  504.     else if (menu->x_pos < 0) menu->x_pos = 0;
  505.     if(menu->y_pos + menu->height > DisplayHeight(display, screen))
  506.         menu->y_pos = DisplayHeight(display, screen) - menu->height;
  507.     else if (menu->y_pos < 0) menu->y_pos = 0;
  508. }
  509.  
  510.  
  511. /*
  512.  * _XMRecomputePane - Internal subroutine to recompute pane
  513.  *              window dependencies.
  514.  */
  515. int
  516. _XMRecomputePane(display, menu, p_ptr, p_num)
  517.     register Display *display;    /* Standard X display variable. */
  518.     register XMenu *menu;    /* Menu object being recomputed. */
  519.     register XMPane *p_ptr;    /* Pane pointer. */
  520.     register int p_num;        /* Pane sequence number. */
  521. {
  522.     register int window_x;    /* Recomputed window X coordinate. */
  523.     register int window_y;    /* Recomputed window Y coordinate. */
  524.     
  525.     unsigned long change_mask;    /* Value mask to reconfigure window. */
  526.     XWindowChanges *changes;    /* Values to use in configure window. */
  527.     
  528.     register Bool config_p = False;    /* Reconfigure pane window? */
  529.  
  530.     /*
  531.      * Update the pane serial number.
  532.      */
  533.     p_ptr->serial = p_num;
  534.  
  535.     /*
  536.      * Recompute window X and Y coordinates.
  537.      */
  538.     switch (menu->menu_style) {
  539.     case LEFT:
  540.         window_x = menu->p_x_off * ((menu->p_count - 1) - p_num);
  541.         window_y = menu->p_y_off * ((menu->p_count - 1) - p_num);
  542.         break;
  543.     case RIGHT:
  544.         window_x = menu->p_x_off * p_num;
  545.         window_y = menu->p_y_off * ((menu->p_count - 1) - p_num);
  546.         break;
  547.     case CENTER:
  548.         window_x = 0;
  549.         window_y = menu->p_y_off * ((menu->p_count - 1) - p_num);
  550.         break;
  551.     default:
  552.         /* Error! Invalid style parameter. */
  553.         _XMErrorCode = XME_STYLE_PARAM;
  554.         return(_FAILURE);
  555.     }
  556.     window_x += menu->x_pos;
  557.     window_y += menu->y_pos;
  558.  
  559.     /*
  560.      * If the newly compute pane coordinates differ from the 
  561.      * current coordinates, reset the current coordinates and
  562.      * reconfigure the pane.
  563.      */
  564.     if (
  565.     (window_x != p_ptr->window_x) ||
  566.     (window_y != p_ptr->window_y)
  567.     ){
  568.     /*
  569.      * Reset the coordinates and schedule
  570.      * the pane for reconfiguration.
  571.      */
  572.     p_ptr->window_x = window_x;
  573.     p_ptr->window_y = window_y;
  574.     config_p = True;
  575.     }
  576.  
  577.     /*
  578.      * If the local pane width and height differs from the
  579.      * menu pane width and height, reset the local values.
  580.      */
  581.     if (
  582.     (p_ptr->window_w != menu->p_width) ||
  583.     (p_ptr->window_h != menu->p_height)
  584.     ){
  585.     /*
  586.      * Reset window width and height and schedule
  587.      * the pane for reconfiguration.
  588.      */
  589.     p_ptr->window_w = menu->p_width;
  590.     p_ptr->window_h = menu->p_height;
  591.     config_p = True;
  592.     }
  593.  
  594.     /*
  595.      * If we need to reconfigure the pane window do it now.
  596.      */
  597.     if (config_p == True) {
  598.     /*
  599.      * If the pane window has already been created then
  600.      * reconfigure the existing window, otherwise queue
  601.      * it for creation with the new configuration.
  602.      */
  603.     if (p_ptr->window) {
  604.         change_mask = (CWX | CWY | CWWidth | CWHeight);
  605.         changes = (XWindowChanges *)malloc(sizeof(XWindowChanges));
  606.         changes->x = p_ptr->window_x;
  607.         changes->y = p_ptr->window_y;
  608.         changes->width = p_ptr->window_w;
  609.         changes->height = p_ptr->window_h;
  610.         
  611.         XConfigureWindow(
  612.                  display,
  613.                  p_ptr->window,
  614.                  change_mask,
  615.                  changes
  616.                  );
  617.         free(changes);
  618.         
  619.     }
  620.     else {
  621.         if (_XMWinQueAddPane(display, menu, p_ptr) == _FAILURE) {
  622.         return(_FAILURE);
  623.         }
  624.     }
  625.     }
  626.  
  627.     /*
  628.      * Recompute label X position.
  629.      */
  630.     switch (menu->p_style) {
  631.     case LEFT:
  632.         p_ptr->label_x = menu->p_x_off + menu->p_fnt_pad;
  633.         break;
  634.     case RIGHT:
  635.         p_ptr->label_x = menu->p_width -
  636.         (p_ptr->label_width + menu->p_x_off + menu->p_fnt_pad);
  637.         break;
  638.     case CENTER:
  639.         p_ptr->label_x = (menu->p_width - p_ptr->label_width) >> 1;
  640.         break;
  641.     default:
  642.         /* Error! Invalid style parameter. */
  643.         _XMErrorCode = XME_STYLE_PARAM;
  644.         return(_FAILURE);
  645.     }
  646.     /*
  647.      * Recompute label Y positions.
  648.      */
  649.     p_ptr->label_uy = menu->p_fnt_pad + menu->p_fnt_info->max_bounds.ascent;
  650.     p_ptr->label_ly = (menu->p_height - menu->p_fnt_pad - menu->p_fnt_info->max_bounds.descent);
  651.  
  652.     /*
  653.      * All went well, return successfully.
  654.      */
  655.     _XMErrorCode = XME_NO_ERROR;
  656.     return(_SUCCESS);
  657. }
  658.  
  659.  
  660.  
  661. /*
  662.  * _XMRecomputeSelection - Internal subroutine to recompute
  663.  *               selection window dependencies.
  664.  */
  665. int
  666. _XMRecomputeSelection(display, menu, s_ptr, s_num)
  667.     register Display *display;
  668.     register XMenu *menu;    /* Menu object being recomputed. */
  669.     register XMSelect *s_ptr;    /* Selection pointer. */
  670.     register int s_num;        /* Selection sequence number. */
  671. {
  672.     register Bool config_s = False;    /* Reconfigure selection window? */
  673.     XWindowChanges *changes;        /* Values to change in configure. */
  674.     unsigned long change_mask;        /* Value mask for XConfigureWindow. */
  675.     
  676.     /*
  677.      * If the selection serial numbers are out of order, begin
  678.      * resequencing selections.  Recompute selection window coordinates
  679.      * and serial number.
  680.      *
  681.      * When selections are created they are given a serial number of
  682.      * -1, this causes this routine to give a new selection
  683.      * its initial coordinates and serial number.
  684.      */
  685.     if (s_ptr->serial != s_num) {
  686.     /*
  687.      * Fix the sequence number.
  688.      */
  689.     s_ptr->serial = s_num;
  690.     /*
  691.      * Recompute window X and Y coordinates.
  692.      */
  693.     s_ptr->window_x = menu->s_x_off;
  694.     s_ptr->window_y = menu->flag_height + (menu->s_y_off * s_num);
  695.     /*
  696.      * We must reconfigure the window.
  697.      */
  698.     config_s = True;
  699.     }
  700.  
  701.     /*
  702.      * If the local selection width and height differs from the
  703.      * menu selection width and height, reset the local values.
  704.      */
  705.     if (
  706.     (s_ptr->window_w != menu->s_width) ||
  707.     (s_ptr->window_h != menu->s_height)
  708.     ){
  709.     /*
  710.      * We must reconfigure the window.
  711.      */
  712.     config_s = True;
  713.     /*
  714.      * Reset window width and height.
  715.      */
  716.     s_ptr->window_w = menu->s_width;
  717.     s_ptr->window_h = menu->s_height;
  718.     }
  719.  
  720.     /*
  721.      * If we need to reconfigure the selection window do it now.
  722.      */
  723.     if (config_s == True) {
  724.     /*
  725.      * If the selection window has already been created then
  726.      * reconfigure the existing window, otherwise queue it
  727.      * for creation with the new configuration.
  728.      */
  729.     if (s_ptr->window) {
  730.         changes = (XWindowChanges *)malloc(sizeof(XWindowChanges));
  731.         change_mask = (CWX | CWY | CWWidth | CWHeight);
  732.         changes = (XWindowChanges *)malloc(sizeof(XWindowChanges));
  733.         changes->x = s_ptr->window_x;
  734.         changes->y = s_ptr->window_y;
  735.         changes->width = s_ptr->window_w;
  736.         changes->height = s_ptr->window_h;
  737.         
  738.         XConfigureWindow(
  739.                  display,
  740.                  s_ptr->window,
  741.                  change_mask,
  742.                  changes
  743.                  );
  744.         free(changes);
  745.         
  746.     }
  747.     else {
  748.         if (_XMWinQueAddSelection(display, menu, s_ptr) == _FAILURE) {
  749.         return(_FAILURE);
  750.         }
  751.     }
  752.     }
  753.  
  754.     /*
  755.      * Recompute label X position.
  756.      */
  757.     switch (menu->s_style) {
  758.     case LEFT:
  759.         s_ptr->label_x = menu->s_bdr_width + menu->s_fnt_pad + s_ptr->window_x;
  760.         break;
  761.     case RIGHT:
  762.         s_ptr->label_x = s_ptr->window_x + menu->s_width -
  763.         (s_ptr->label_width + menu->s_bdr_width + menu->s_fnt_pad);
  764.         break;
  765.     case CENTER:
  766.         s_ptr->label_x = s_ptr->window_x + ((menu->s_width - s_ptr->label_width) >> 1);
  767.         break;
  768.     default:
  769.         /* Error! Invalid style parameter. */
  770.         _XMErrorCode = XME_STYLE_PARAM;
  771.         return(_FAILURE);
  772.     }
  773.     /*
  774.      * Recompute label Y position.
  775.      */
  776.     s_ptr->label_y = s_ptr->window_y + menu->s_fnt_info->max_bounds.ascent + menu->s_fnt_pad + menu->s_bdr_width;
  777.     
  778.     /*
  779.      * All went well, return successfully.
  780.      */
  781.     _XMErrorCode = XME_NO_ERROR;
  782.     return(_SUCCESS);
  783. }
  784.  
  785.  
  786.  
  787. /*
  788.  * _XMTransToOrigin - Internal subroutine to translate the point at
  789.  *              the center of the current pane and selection to the 
  790.  *              the menu origin.
  791.  *
  792.  *    WARNING! ******    Be certain that all menu dependencies have been
  793.  *            recomputed before calling this routine or
  794.  *            unpredictable results will follow.
  795.  */
  796. _XMTransToOrigin(display, menu, p_ptr, s_ptr, x_pos, y_pos, orig_x, orig_y)
  797.     Display *display;        /* Not used. Included for consistency. */
  798.     register XMenu *menu;    /* Menu being computed against. */
  799.     register XMPane *p_ptr;    /* Current pane pointer. */
  800.     register XMSelect *s_ptr;    /* Current selection pointer. */
  801.     int x_pos;            /* X coordinate of point to translate. */
  802.     int y_pos;            /* Y coordinate of point to translate. */
  803.     int *orig_x;        /* Return value X coord. of the menu origin. */
  804.     int *orig_y;        /* Return value Y coord. of the menu origin. */
  805. {
  806.     register int l_orig_x;    /* Local X coordinate of the menu origin. */
  807.     register int l_orig_y;    /* Local Y coordinate of the menu origin. */
  808.     
  809.     /*
  810.      * Translate the menu origin such that the cursor hot point will be in the
  811.      * center of the desired current selection and pane.
  812.      * If the current selection pointer is NULL then assume that the hot point
  813.      * will be in the center of the current pane flag.
  814.      */
  815.  
  816.     if (s_ptr == NULL) {
  817.     /*
  818.      * Translate from the center of the pane flag to the upper left
  819.      * of the current pane window.
  820.      */
  821.     l_orig_x = x_pos - (menu->p_width >> 1) - menu->p_bdr_width;
  822.     l_orig_y = y_pos - (menu->flag_height >> 1) - menu->p_bdr_width;
  823.     }
  824.     else {
  825.     /*
  826.      * First translate from the center of the current selection
  827.      * to the upper left of the current selection window.
  828.      */
  829.     l_orig_x = x_pos - (menu->s_width >> 1);
  830.     l_orig_y = y_pos - (menu->s_height >> 1);
  831.  
  832.     /*
  833.      * Then translate to the upper left of the current pane window.
  834.      */
  835.     l_orig_x -= (s_ptr->window_x + menu->p_bdr_width);
  836.     l_orig_y -= (s_ptr->window_y + menu->p_bdr_width);
  837.     }
  838.  
  839.     /*
  840.      * Finally translate to the upper left of the menu.
  841.      */
  842.     l_orig_x -= (p_ptr->window_x - menu->x_pos);
  843.     l_orig_y -= (p_ptr->window_y - menu->y_pos);
  844.  
  845.     /*
  846.      * Set the return values.
  847.      */
  848.     *orig_x = l_orig_x;
  849.     *orig_y = l_orig_y;
  850. }
  851.  
  852. /*
  853.  * _XMRefreshPane - Internal subroutine to completely refresh
  854.  *            the contents of a pane.
  855.  */
  856. _XMRefreshPane(display, menu, pane)
  857.     register Display *display;
  858.     register XMenu *menu;
  859.     register XMPane *pane;
  860. {
  861.     register XMSelect *s_list = pane->s_list;
  862.     register XMSelect *s_ptr;
  863.  
  864.     /*
  865.      * First clear the pane. 
  866.      */
  867.     XClearWindow(display, pane->window);
  868.     if (!pane->activated) {
  869.     XFillRectangle(display,
  870.                pane->window,
  871.                menu->inverse_select_GC,
  872.                pane->label_x - menu->p_fnt_pad,
  873.                pane->label_uy - menu->p_fnt_info->max_bounds.ascent - menu->p_fnt_pad,
  874.                pane->label_width + (menu->p_fnt_pad << 1),
  875.                menu->flag_height);
  876.  
  877.     XFillRectangle(display,
  878.                pane->window,
  879.                menu->inverse_select_GC,
  880.                pane->label_x - menu->p_fnt_pad,
  881.                pane->label_ly - menu->p_fnt_info->max_bounds.ascent - menu->p_fnt_pad,
  882.                pane->label_width + (menu->p_fnt_pad << 1),
  883.                menu->flag_height);
  884.     }
  885.     if (!pane->active) {
  886.     XDrawString(display,
  887.             pane->window,
  888.             menu->inact_GC,
  889.             pane->label_x, pane->label_uy,
  890.             pane->label, pane->label_length);
  891.     XDrawString(display,
  892.             pane->window,
  893.             menu->inact_GC,
  894.             pane->label_x, pane->label_ly,
  895.             pane->label, pane->label_length);
  896.     }
  897.     else {
  898.     XDrawString(display,
  899.              pane->window,
  900.              menu->pane_GC,
  901.              pane->label_x, pane->label_uy,
  902.              pane->label, pane->label_length);
  903.     XDrawString(display,
  904.              pane->window,
  905.              menu->pane_GC,
  906.              pane->label_x, pane->label_ly,
  907.              pane->label, pane->label_length);
  908.  
  909.     /*
  910.      * Finally refresh each selection if the pane is activated.
  911.      */
  912.     if (pane->activated) {
  913.         for (s_ptr = s_list->next; s_ptr != s_list; s_ptr = s_ptr->next)
  914.         _XMRefreshSelection(display, menu, s_ptr);
  915.     }
  916.     }
  917. }
  918.     
  919.     
  920.  
  921.  
  922. /*
  923.  * _XMRefreshSelection - Internal subroutine that refreshes 
  924.  *             a single selection window.
  925.  */
  926. _XMRefreshSelection(display, menu, select)
  927.     register Display *display;
  928.     register XMenu *menu;
  929.     register XMSelect *select;
  930. {
  931.     register int width = select->window_w;
  932.     register int height = select->window_h;
  933.     register int bdr_width = menu->s_bdr_width;
  934.     
  935.     if (select->activated) {
  936.     if (menu->menu_mode == INVERT) {
  937.         XFillRectangle(display, 
  938.                select->parent_p->window,
  939.                menu->normal_select_GC,
  940.                select->window_x, select->window_y,
  941.                width, height); 
  942.         XDrawString(display,
  943.             select->parent_p->window,
  944.             menu->inverse_select_GC,
  945.             select->label_x,
  946.             select->label_y,
  947.             select->label, select->label_length);
  948.     }
  949.         else {
  950.             /*
  951.          * Using BOX mode.
  952.              * Since most drawing routines with arbitrary width lines
  953.          * are slow compared to raster-ops lets use a raster-op to
  954.          * draw the boxes.
  955.              */
  956.         
  957.         XDrawRectangle(display,
  958.                select->parent_p->window,
  959.                menu->normal_select_GC,
  960.                select->window_x + (bdr_width >> 1),
  961.                select->window_y + (bdr_width >> 1 ),
  962.                width - bdr_width,
  963.                height - bdr_width);
  964.         XDrawString(display,
  965.             select->parent_p->window,
  966.             menu->normal_select_GC,
  967.             select->label_x,
  968.             select->label_y,
  969.             select->label, select->label_length);
  970.         }
  971.     }
  972.     else {
  973.     XClearArea(display, 
  974.            select->parent_p->window,
  975.            select->window_x, select->window_y,
  976.            width, height,
  977.            False);
  978.     if (select->active) {
  979.         XDrawString(display,
  980.             select->parent_p->window,
  981.             menu->normal_select_GC,
  982.             select->label_x,
  983.             select->label_y,
  984.             select->label, select->label_length);
  985.     }
  986.     else {
  987.         XDrawString(display,
  988.             select->parent_p->window,
  989.             menu->inact_GC,
  990.             select->label_x,
  991.             select->label_y,
  992.             select->label, select->label_length);
  993.     }
  994.     }
  995. }
  996.  
  997.